
import java.util.ArrayList;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author Marc
 */
class Driver extends Person {
    private ArrayList <Point> trace;
    private ArrayList <Integer> p_23;
    public int traceDistance;

    public Driver(int id, Point ini, Point fi){
        super(id, ini, fi);
        trace = new ArrayList <Point>();
        p_23 = new ArrayList<Integer>();
        traceDistance = dist(ini, fi);
    }

     public Driver(Driver dr){
         super(dr.getid(), dr.getini(), dr.getfi());
         trace = new ArrayList <Point>();
         p_23 = new ArrayList<Integer>();
         traceDistance = dr.getTraceDistance();
         for (int i = 0; i < dr.getTrace().size(); ++i){
             trace.add(dr.getTrace().get(i));
         }
         for (int i = 0; i < dr.p_23.size(); ++i){
             p_23.add(dr.p_23.get(i));
         }
     }

    public void addTraveller(Person p){
        if (p != null){
            trace.add(p.getini());
            trace.add(p.getfi());
            p_23.add(p.getid());
            p_23.add(0-p.getid());
            //updateDist(p.getini(), p.getfi());
            traceDistance=(CtraceDistance());
        }
    }
    
    private void updateDist(Point ini, Point fi){
        int n = trace.size();
        if (n == 2) {
            traceDistance = dist(this.getini(), ini);
            traceDistance += dist(ini, fi);
            traceDistance += dist(fi, this.getfi());
        }
        else {
            traceDistance -= dist(trace.get(n-1), this.getfi());
            traceDistance += dist(trace.get(n-1), ini);
            traceDistance += dist(ini, fi);
            traceDistance += dist(fi, this.getfi());
        }
    }

    public boolean deleteTraveller(int id){
        boolean b = false;
        for (int i = 0; i < p_23.size(); ++i){
            if (p_23.get(i) == id || p_23.get(i) == 0-id) {

                p_23.remove(i);
                trace.remove(i);
                --i;
                b = true;
            }
        }
        traceDistance=(CtraceDistance());
        return b;
    }

    public void addTravellers (ArrayList <Point> NewTrace, ArrayList <Integer> Newp_23){
        int traceSize = NewTrace.size();
        for (int i = 0; i < traceSize; ++i) trace.add(NewTrace.get(i));
        int Ntravellers = Newp_23.size();
        for (int i = 0; i < Ntravellers; ++i) p_23.add(Newp_23.get(i));
    }

    public ArrayList <Integer> getp_23(){
        return p_23;
    }

    public int getNTravellers (){
        return p_23.size() / 2;
    }

    public ArrayList <Point> getTrace(){
        return trace;
    }

    public int CtraceDistance() {
        int sum;
        if (trace.size() == 0)sum = dist(this.getini(), this.getfi());
        else {
            sum = dist(this.getini(), trace.get(0));
            int m = trace.size();
            for (int j = 0; j < m-1; ++j){
                sum += dist(trace.get(j), trace.get(j+1));
            }
            sum += dist(trace.get(m-1), this.getfi());
            }
        return sum;
    }

    public int getTraceDistance(){
        return traceDistance;
    }

    public void setTraceDistance(int value){
        traceDistance = value;
    }

    private int dist(Point p1, Point p2){
        int d = Math.abs(p1.getx()-p2.getx()) + Math.abs(p1.gety()-p2.gety());
        return d;
    }


    public boolean swapTravellers(int id, boolean ini){
        int cont = 0;
        boolean b = false;
        for (int i = 0; i < p_23.size()-1 && !b; ++i){
            if (p_23.get(i) > 0)++cont;
            else --cont;
            if (p_23.get(i) == id && ini) {
                if (0-id == p_23.get(i + 1))
                    return false;
                p_23.remove(i);
                Point aux = trace.get(i);
                trace.remove(i);
                p_23.add(i+1, id);
                trace.add(i+1,aux);
                b = false;                
            }
            else if (p_23.get(i) == 0-id && !ini){
                if (p_23.get(i+1)>0 && cont == 2)
                    return false;
                p_23.remove(i);
                Point aux = trace.get(i);
                trace.remove(i);
                p_23.add(i+1, 0-id);
                trace.add(i+1,aux);
                b = false;
            }
        }
        traceDistance = CtraceDistance();
        return true;
    }

    public boolean contains(Person p) {
        for (int i = 0; i < p_23.size(); ++i){
            if (p_23.get(i) == p.getid())
                return true;
        }
        return false;
    }
    
    public int[] getIdTravellers() {
        int ids[] = new int[p_23.size()/2];
        int k = 0;
        for (int i = 0; i < p_23.size(); ++i) {
            if (p_23.get(i) > 0)
                ids[k++] = p_23.get(i);
        }
        return ids;
    }

    boolean swapInCar(int id1, int id2) {
        int ini1, ini2, fi1, fi2;
        ini1 = ini2 = fi1 = fi2 = -1;
        for (int i = 0; i < p_23.size(); ++i) {
            if (p_23.get(i) == id1)
                ini1 = i;
            else if (p_23.get(i) == id2)
                ini2 = i;
            else if (p_23.get(i) == 0-id1)
                fi1 = i;
            else if (p_23.get(i) == 0-id2)
                fi2 = i;
        }
        if (ini1 == -1 || ini2 == -1 || fi1 == -1 || fi2 == -1)
            return false;
        else {
            int aux = p_23.get(ini1);
            p_23.set(ini1, p_23.get(ini2));
            p_23.set(ini2, aux);
            aux = p_23.get(fi1);
            p_23.set(fi1, p_23.get(fi2));
            p_23.set(fi2, aux);
            Point aux2 = trace.get(ini1);
            trace.set(ini1, trace.get(ini2));
            trace.set(ini2, aux2);
            aux2 = trace.get(fi1);
            trace.set(fi1, trace.get(fi2));
            trace.set(fi2, aux2);
        }
        return true;
    }
}
